﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;

namespace CommonUtils
{
    /// <summary>
    /// 字符串工具
    /// </summary>
    public static partial class StringUtil
    {
        public static char[] CommaAndWrap = { ',', '\r', '\n' };

        public static string[] Digits = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" };
        public static string[] Letters = { "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z" };

        public static char[] Wrap = { '\r', '\n' };

        public static string AddTimestamp(this string value)
        => value + "?t=" + TimeUtil.NowStamp;

        public static string NewId()
        => Guid.NewGuid().ToString();

        public static string[] SplitByComma(this string value)
        => value.Split(',');

        public static string[] SplitByWrap(this string value)
        => value.Split(Wrap, StringSplitOptions.RemoveEmptyEntries);

        public static string[] SplitByCommaAndWrap(this string value)
        => value.Split(CommaAndWrap, StringSplitOptions.RemoveEmptyEntries);

        //按char分割
        public static string[] SplitChars(this string value)
        => value.Select(m => m.ToString()).Where(m => IsNotEmpty(m)).ToArray();

        public static string[] SplitByPunctuations(this string value)
        => value.Split(StringIdentifier.Punctuations, StringSplitOptions.RemoveEmptyEntries);

        public static string Join(params object[] values)
        => values.Join(',');

        public static string[] OrderByLengthAsc(this string[] lines)
        {
            var list = lines.ToList();
            list.Sort(delegate (string a, string b)
            {
                return a.Length - b.Length;
            });
            return list.ToArray();
        }

        public static string[] SortByLengthAsc(this string[] lines)
        => OrderByLengthAsc(lines);

        public static string[] OrderByLengthDesc(this string[] lines)
        {
            var list = lines.ToList();
            list.Sort(delegate (string a, string b)
            {
                return b.Length - a.Length;
            });
            return list.ToArray();
        }

        public static string[] SortByLengthDesc(this string[] lines)
        => OrderByLengthDesc(lines);

        public static string[] RemoveCotainsWrap(this string[] lines)
        => lines.Where(m => !m.Contains('\n')).ToArray();

        public static string[] GetByRegex(this string text, string regexRule)
        {
            var regex = new Regex(regexRule);
            var match = regex.Match(text);
            var list = new List<string>();
            while (match.Success)
            {
                list.Add(match.Result("$0"));
                match = match.NextMatch();
            }
            return list.ToArray();
        }

        public static string[] GetTimeStrings(this string text)
        => text.GetByRegex("[0-9]+-[0-9]+-[0-9]+ [0-9]+:[0-9]+:[0-9]+.[0-9]+");

        public static string ToStringEx(this object value)
        => value == null ? null : value.ToString();

        public static bool Contains(this string text, IEnumerable<string> keywords)
        {
            if (string.IsNullOrEmpty(text))
                return false;

            foreach (var keyword in keywords)
            {
                if (string.IsNullOrEmpty(keyword))
                    continue;
                if (text.Contains(keyword))
                    return true;
            }

            return false;
        }

        public static string GetContainsValue(this string text, IEnumerable<string> keywords)
        {
            if (string.IsNullOrEmpty(text))
                return text;

            foreach (var keyword in keywords)
            {
                if (string.IsNullOrEmpty(keyword))
                    continue;
                if (text.Contains(keyword))
                    return keyword;
            }

            return text;
        }

        public static string ToPercentage(this float value)
        => (value * 100).ToString("0.00") + "%";

        public static string To0Percentage(this float value)
        => (value * 1000).ToString("0.00") + "‰";

        public static string To00Percentage(this float value)
        => (value * 10000).ToString("0.00") + "%%(万分)";

        public static string ToPercentage(this double value)
        => (value * 100).ToString("0.00") + "%";

        public static string To0Percentage(this double value)
        => (value * 1000).ToString("0.00") + "‰";

        public static string To00Percentage(this double value)
        => (value * 10000).ToString("0.00") + "%%(万分)";

        public static bool IsUpper(this char letter)
        => letter >= 'A' && letter <= 'Z';

        private static readonly int _upperDiff = 'A' - 'a';

        public static char ToUpper(this char letter)
        => (char)(letter + _upperDiff);

        public static char ToLower(this char letter)
        => char.ToLower(letter);

        public static string UpperFirst(this string value)
        {
            var builder = new StringBuilder();
            builder.Append(value[0].ToUpper());
            for (var index = 1; index < value.Length; index++)
                builder.Append(value[index]);
            return builder.ToString();
        }

        public static string LowerFirst(this string value)
        {
            var builder = new StringBuilder();
            builder.Append(value[0].ToLower());
            for (var index = 1; index < value.Length; index++)
                builder.Append(value[index]);
            return builder.ToString();
        }

        public static string BlankToCamel(this string value, bool firstUpper = true)
        {
            bool blank = firstUpper;
            var sb = new StringBuilder();
            foreach (var element in value)
            {
                if (element == '_')
                {
                    blank = true;
                    continue;
                }
                if (blank)
                {
                    blank = false;
                    sb.Append(element.ToUpper());
                    continue;
                }
                sb.Append(element);
            }
            return sb.ToString();
        }

        public const char Blank = '_';

        public static string CamelToUnderLine(this string value)
        {
            var sb = new StringBuilder();
            foreach (var element in value)
            {
                if (element.IsUpper())
                {
                    if (sb.Length > 0)
                        sb.Append(Blank);
                    sb.Append(element.ToLower());
                    continue;
                }
                sb.Append(element);
            }
            return sb.ToString();
        }
        public static string CamelToBlank(this string value)
        => value.CamelToUnderLine();

        /// <summary>
        /// 添加双引号
        /// </summary>
        public static string AddDoubleQuotes(this string text, bool check = false)
        {
            if (check && text.StartsWith('"'))
                return text;
            return string.Format("\"{0}\"", text);
        }

        public static string[] AddDoubleQuotes(this string[] texts)
            => texts.Select(x => x.AddDoubleQuotes()).ToArray();

        /// <summary>
        /// 添加双引号
        /// </summary>
        public static string AddSingleQuotes(this string text, bool check = false)
        {
            if (check && text.StartsWith('\''))
                return text;
            return string.Format("'{0}'", text);
        }

        /// <summary>
        /// 附加(非引用)
        /// </summary>
        public static string Append(this string left, char sperator, params object[] rights)
        {
            var sb = new StringBuilder(left);
            foreach (var right in rights)
            {
                if (sb.Length > 0)
                    sb.Append(sperator);
                sb.Append(right);
            }
            return sb.ToString();
        }

        /// <summary>
        /// 附加(非引用)
        /// </summary>
        public static string Append(this string left, params object[] rights)
        {
            var sb = new StringBuilder(left);
            foreach (var right in rights)
                sb.Append(right);
            return sb.ToString();
        }

        public static void Append(this StringBuilder sb, params object[] args)
        {
            foreach (var arg in args)
                sb.Append(arg);
        }

        public static void Append(this StringBuilder sb, string format, params object[] args)
        => sb.Append(format.Format(args));

        public static void Insert(this StringBuilder sb, string value)
        => sb.Insert(0, value);

        public static void InsertLine(this StringBuilder sb)
        => sb.Insert("\r\n");

        public static void InsertLine(this StringBuilder sb, string format, params object[] args)
        {
            sb.InsertLine();
            sb.Insert(Format(format, args));
        }

        public static void LineAppend(this StringBuilder sb, string format, params object[] args)
        {
            sb.AppendLine();
            sb.Append(Format(format, args));
        }

        public static void AppendLine(this StringBuilder sb, string format, params object[] args)
        => sb.AppendLine(format.Format(args));

        public static void AppendLines(this StringBuilder sb, params object[] args)
        {
            foreach (var arg in args)
                sb.AppendLine(arg.ToString());
        }

        public static void AppendDividinLine(this StringBuilder sb, params object[] args)
        => sb.AppendLine(StringIdentifier.DividinLine);

        public static string AppendNextLine(this string left, params object[] rights)
        {
            var sb = new StringBuilder(left);
            foreach (var right in rights)
            {
                sb.AppendLine();
                sb.Append(right);
            }
            return sb.ToString();
        }

        /// <summary>
        /// 包含关键字
        /// </summary>
        public static bool Contains(this string str, params string[] keys)
        {
            foreach (string key in keys)
                if (str.Contains(key))
                    return true;
            return false;
        }

        public static bool ContainsIgnoreCase(this string str, params string[] keys)
        {
            str = str.ToUpper();
            foreach (string key in keys)
                if (str.Contains(key.ToUpper()))
                    return true;
            return false;
        }

        public static bool Contains(this string text, char single)
        => text.IndexOf(single) != -1;

        public static int CountOf(this string text, char key)
        => CountOf(text, key.ToString());

        /// <summary>
        /// key数量
        /// </summary>
        public static int CountOf(this string text, string key)
        => (text.Length - text.Replace(key, "").Length) / key.Length;

        /// <summary>
        /// 截取字符串后部
        /// </summary>
        public static string End(this string src, int length)
        {
            if (src.Length < length)
                return src;
            return src.Substring(src.Length - length);
        }

        /// <summary>
        /// 判断起始字符
        /// </summary>
        public static bool EndWith(this string text, params char[] chars)
        {
            int index = text.Length - 1;
            foreach (char ch in chars)
                if (text[index] == ch)
                    return true;
            return false;
        }

        /// <summary>
        /// 以end结尾
        /// </summary>
        public static bool EndWith(this string text, string end)
        {
            if (text.Length < end.Length)
                return false;
            return text.Substring(text.Length - end.Length, end.Length) == end;
        }

        /// <summary>
        /// 多字符串比较
        /// </summary>
        public static bool Equals(this string str, params string[] strs)
        {
            foreach (var item in strs)
                if (str == item)
                    return true;
            return false;
        }

        public static bool EqualsCaseIgnored(this string left, params string[] rights)
        => EqualsWithoutCase(left, rights);

        /// <summary>
        /// 比较开始是否一样
        /// </summary>
        public static bool EqualsStart(this string left, string right)
        {
            if (left.Length > right.Length)
                left = left.Substring(0, right.Length);
            else
                right = right.Substring(0, left.Length);
            return left == right;
        }

        /// <summary>
        /// 忽略大小写判断是否相等
        /// </summary>
        public static bool EqualsWithoutCase(this string left, params string[] rights)
        {
            var lowerLeft = left.ToLower();
            foreach (var right in rights)
                if (lowerLeft == right.ToLower())
                    return true;
            return false;
        }

        /// <summary>
        /// 长度不够 用字符填充
        /// </summary>
        public static string Fill(this string text, int length, char ch = '0')
        {
            if (text.Length >= length)
                return text;

            var sb = new StringBuilder();
            for (int index = 0; index < length - text.Length; index++)
                sb.Append(ch);
            sb.Append(text);
            return sb.ToString();
        }

        /// <summary>
        /// 删除数字
        /// </summary>
        public static string FiltDigit(this string value)
        => value.Remove(StringIdentifier.DigitChars);

        public static string DisableHtml(this string html)
        => html.Replace("<", "&lt;").Replace(">", "&gt;");

        public static string FiltHtml(this string html)
        {
            var sb = new StringBuilder();
            bool append = true;
            foreach (var ch in html)
            {
                if (ch == '<')
                    append = false;
                if (append)
                    sb.Append(ch);
                if (ch == '>')
                    append = true;
            }
            return sb.ToString();
        }

        /// <summary>
        /// 支持带花括号的字符串格式化
        /// </summary>
        public static string FormatWhichContainsMark(string format, params object[] args)
        {
            if (args.Length == 0)
                return format;

            var left = "{";
            var right = "}";
            var leftMark = "!left!";
            var rightMark = "!right!";

            format = format.Replace(left, leftMark).Replace(right, rightMark);

            for (int index = 0; index < args.Length; index++)
                format = format.Replace(leftMark + index + rightMark, left + index + right);

            format = string.Format(format, args);

            return format.Replace(leftMark, left).Replace(rightMark, right);
        }

        const string LeftBrace = "{";
        const string RightBrace = "}";
        const string Brace = "{}";

        const string LeftBraceMark = "_LeftBracesMark_";
        const string RightBraceMark = "_RightBracesMark_";
        const string BraceMark = "_LeftBracesMark__RightBracesMark_";

        /// <summary>
        /// 支持{}格式
        /// </summary>
        public static string Format(this object value, params object[] args)
        {
            if (value == null)
                return "[value:null]";

            var format = value.ToString();
            if (args.Length == 0)
                return format;
            format = format.Replace(LeftBrace, LeftBraceMark).Replace(RightBrace, RightBraceMark);
            for (var index = 0; index < args.Length; index++)
                format = format.Replace(LeftBraceMark + index + RightBraceMark, LeftBrace + index + RightBrace);
            var values = format.Split(BraceMark);
            if (values.Length > 1)
            {
                format = values[0];
                for (int index = 1; index < values.Length; index++)
                    format += "{" + (index - 1) + "}" + values[index];
            }
            return string.Format(format, args).Replace(LeftBraceMark, LeftBrace).Replace(RightBraceMark, RightBrace);
        }

        /// <summary>
        /// 截取字符串前部
        /// </summary>
        public static string Front(this string src, int length)
        {
            if (src.Length < length)
                return src;

            return src.Substring(0, length);
        }

        /// <summary>
        /// 获取中间部分 默认包含两头标签
        /// 默认 bool containsTag = true，为了强调，取消默认
        /// </summary>
        public static string[] GetBetweens(this string text, string start, string end, bool containsTag)
        {
            if (text.IsEmpty())
                return new string[0];
            var betweens = new List<string>();
            int startIndex = text.IndexOf(start);
            int endIndex;
            int tempStartIndex;
            while (startIndex != -1)
            {
                endIndex = text.IndexOf(end, startIndex + start.Length);

                if (endIndex == -1)
                    break;

                tempStartIndex = text.IndexOf(start, startIndex + start.Length);
                while (tempStartIndex != -1 && tempStartIndex < endIndex)
                {
                    startIndex = tempStartIndex;
                    tempStartIndex = text.IndexOf(start, startIndex + start.Length);
                }

                if (containsTag)
                    betweens.Add(text.SubstringByIndex(startIndex, endIndex + end.Length));
                else
                    betweens.Add(text.SubstringByIndex(startIndex + start.Length, endIndex));

                startIndex = text.IndexOf(start, endIndex + end.Length);
            }
            return betweens.Distinct().ToArray();
        }

        public static string GetBetween(this string text, string start, string end, bool containsTag)
        => GetBetweens(text, start, end, containsTag).FirstOrDefault();

        /// <summary>
        /// 文本编码
        /// </summary>
        public static byte[] GetBytes(string text, Encoding encoding = null)
        => text.GetBytes(encoding);

        /// <summary>
        /// 获取描述
        /// </summary>
        public static string GetDescription(this string text)
        => text.Front(20);

        /// <summary>
        /// 获取数值信息
        /// </summary>
        public static string GetDigitInfo(decimal value, bool IsPlusContained = false)
        {
            string symbol = "";

            if (IsPlusContained && value > 0)
                symbol = "+";

            if (value < 0)
            {
                symbol = "-";
                value = -value;
            }

            if (value < 10000)
                return symbol + value.ToString("0.00");

            decimal valueD = value / 10000;

            if (valueD < 10000)
                return symbol + valueD.ToString("0.00") + "万";

            valueD /= 10000;
            return symbol + valueD.ToString("0.00") + "亿";
        }

        /// <summary>
        /// 获取数值信息
        /// </summary>
        public static string GetDigitInfo(int value, int baseValue = 16)
        => Convert.ToString(value, baseValue);

        /// <summary>
        /// 只取数字
        /// </summary>
        public static string GetDigits(this string text)
        {
            StringBuilder sb = new StringBuilder();
            foreach (char ch in text)
                if (ch >= '0' && ch <= '9')
                    sb.Append(ch);
            return sb.ToString();
        }

        /// <summary>
        /// 文件大小单位换算
        /// </summary>
        public static string GetFileSize(object fileLengthObject)
        {
            long fileLength = ConvertUtil.ToLong(fileLengthObject);

            if (fileLength / 1024 >= 1024 * 1024 * 1024)
                return (fileLength / (1024 * 1024 * 1024 * 1024.0)).ToString("0.0") + "TB";

            if (fileLength >= 1024 * 1024 * 1024)
                return (fileLength / (1024 * 1024 * 1024.0)).ToString("0.0") + "GB";

            if (fileLength >= 1024 * 1024)
                return (fileLength / (1024 * 1024.0)).ToString("0.0") + "MB";

            if (fileLength >= 1024)
                return (fileLength / 1024.0).ToString("0.0") + "KB";

            if (fileLength < 1024)
                return "<1KB";

            return fileLengthObject + "B";
        }

        /// <summary>
        /// 获取两值之间字符串
        /// </summary>
        public static string GetFill(string src, string start, string end, bool isTagContained)
        {
            string fill = null;
            int startIndex = src.IndexOf(start);
            if (startIndex > -1)
            {
                int endIndex = src.IndexOf(end, startIndex + start.Length);
                if (endIndex > -1)
                {
                    fill = src.Substring(startIndex + start.Length, endIndex - (startIndex + start.Length));
                    if (isTagContained)
                    {
                        fill = start + fill + end;
                    }
                }
            }
            return fill;
        }

        /// <summary>
        /// 获取两字符之前的关键字
        /// </summary>
        public static string[] GetFills(string src, string start, string end, bool isTagContained = false)
        {
            List<string> listFill = new List<string>();

            if (string.IsNullOrEmpty(src) || string.IsNullOrEmpty(start) || string.IsNullOrEmpty(end))
                return listFill.ToArray();

            string tempSrc = src;
            int endIndex = tempSrc.IndexOf(end);
            while (endIndex > -1)
            {
                string fillContainer = tempSrc.Substring(0, endIndex);
                int startIndex = fillContainer.LastIndexOf(start);
                if (startIndex > -1)
                {
                    string fill = fillContainer.Substring(startIndex + start.Length, endIndex - startIndex - start.Length);
                    if (isTagContained)
                    {
                        fill = start + fill + end;
                    }
                    listFill.Add(fill);
                }

                if (endIndex + end.Length + 1 > tempSrc.Length)
                    break;

                tempSrc = tempSrc.Substring(endIndex + end.Length, tempSrc.Length - endIndex - end.Length);
                endIndex = tempSrc.IndexOf(end);
            }
            return listFill.ToArray();
        }

        /// <summary>
        /// 加长填充字符
        /// </summary>
        public static string GetFillsAppendedString(string src, string start, string end, string append)
        {
            string[] fills = GetFills(src, start, end, true);
            foreach (string fill in fills)
                src = src.Replace(fill, fill + append);
            return src;
        }

        /// <summary>
        /// 改变填充字符
        /// </summary>
        public static string GetFillsChangedString(string src, string start, string end, string newValue)
        => GetFillsChangedString(src, start, end, end, newValue);

        /// <summary>
        /// 改变填充字符
        /// </summary>
        public static string GetFillsChangedString(string src, string start, string end, string oldValue, string newValue)
        {
            string[] fills = GetFills(src, start, end, true);
            foreach (string fill in fills)
                src = src.Replace(fill, fill.Replace(oldValue, newValue));
            return src;
        }

        /// <summary>
        /// 删除填充字符
        /// </summary>
        public static string GetFillsDeletedString(string src, string start, string end, bool isTagContained)
        {
            var fills = GetFills(src, start, end, isTagContained);
            return GetFillsDeletedString(src, fills);
        }

        /// <summary>
        /// 删除填充字符
        /// </summary>
        public static string GetFillsDeletedString(string src, string[] fills)
        {
            foreach (string fill in fills)
                src = src.Replace(fill, "");
            return src;
        }

        /// <summary>
        /// 删除填充字符
        /// </summary>
        public static string GetFillsInsertedString(string src, string start, string end, string append)
        {
            var fills = GetFills(src, start, end, true);
            foreach (string fill in fills)
            {
                src = src.Replace(fill, fill.Replace(end, append + end));
            }
            return src;
        }

        /// <summary>
        /// 替换填充字符
        /// </summary>
        public static string GetFillsReplacedString(string src, string start, string end, string newValue)
        {
            var fills = GetFills(src, start, end, true);
            foreach (string fill in fills)
            {
                src = src.Replace(fill, newValue);
            }
            return src;
        }

        /// <summary>
        /// 获取字符串前半部分
        /// </summary> 
        public static string GetFront(string src, string separator)
        {
            int index = src.IndexOf(separator);
            if (index > -1)
                src = src.Substring(0, index);
            return src;
        }

        public static string GetGuidLowerNoBar(string tail = null)
        => Guid.NewGuid().ToString().ToLower().RemoveChar('-') + tail;

        public static string GetGuidLowerWithBars(string tail = null)
        => Guid.NewGuid().ToString().ToLower() + tail;

        public static string GetGuidUpperNoBar(string tail = null)
        => Guid.NewGuid().ToString().ToUpper().RemoveChar('-') + tail;

        public static string GetGuidUpperWithBars(string tail = null)
        => Guid.NewGuid().ToString().ToUpper() + tail;

        public static string GetGuid(string tail = null)
        => Guid.NewGuid() + tail;

        public static string GetGuidWithoutBars(string tail = null)
        => GetGuid(tail).Remove("-");

        public static string GetUpperredGuidWithoutBars(string tail = null)
        => GetGuidWithoutBars(tail).ToUpper();

        /// <summary>
        /// 将字符串拼接
        /// </summary>
        public static string GetJoinedString(string str1, string str2, string separator = "")
        => string.IsNullOrEmpty(str1) ? str2 : (str1 + separator + str2);

        /// <summary>
        /// 将字符串数组拼接为字符串
        /// </summary>
        public static string GetJoinedString(string[] strs, string separator = "")
        => string.Join(separator, strs);

        /// <summary>
        /// 获取关键字
        /// </summary>
        public static string GetKeywords(this string text)
        {
            text = text.RemovePunctuations();
            string[] lines = text.GetLines();
            string keywords = "";
            foreach (string line in lines)
            {
                if (!string.IsNullOrWhiteSpace(line))
                {
                    keywords += line.End(4) + ',';
                }
            }
            return keywords;
        }

        /// <summary>
        /// 只取字母数字
        /// </summary>
        public static string GetLettersAndDigits(this string text)
        {
            StringBuilder sb = new StringBuilder();
            foreach (char ch in text)
            {
                if (ch >= '0' && ch <= '9')
                    sb.Append(ch);

                if (ch >= 'a' && ch <= 'z')
                    sb.Append(ch);

                if (ch >= 'A' && ch <= 'Z')
                    sb.Append(ch);
            }
            return sb.ToString();
        }

        /// <summary>
        /// 获取文本行
        /// </summary>
        public static string[] GetLines(this string text, StringSplitOptions splitOptions = StringSplitOptions.None)
        => text.RemoveChar('\r').Split('\n', splitOptions);

        public static string[] GetLinesWithOutEmpty(this string text)
        => text.SplitAndRemoveEmpty(StringIdentifier.LineSeparators);

        public static string[] GetLinesStartsWith(this string text, params string[] keywords)
        => text.GetLines().Where(m => StartsWith(m, keywords)).ToArray();

        /// <summary>
        /// 获取两值之间字符串
        /// </summary>
        public static string GetMiddleString(string src, string start, string end, bool isTagContained = false)
        => GetFill(src, start, end, isTagContained);

        /// <summary>
        /// 获取两字符之前的字符数组
        /// </summary>
        public static string[] GetMiddleStrings(this string src, string start, string end, bool isTagContained = false)
        => GetFills(src, start, end, isTagContained);

        public static int GetNumber(this string text)
        => text.GetDigits().ToInt();

        /// <summary>
        /// 获取关键字出现次数
        /// </summary>
        public static int GetOccuredTime(string sentence, string word)
        {
            int i = -1, count = -1;
            do
            {
                i = sentence.IndexOf(word, i + 1);
                count++;
            }
            while (i != -1);
            return count;
        }

        /// <summary>
        /// 获取百分比字符串
        /// </summary>
        public static string GetRateInfo(decimal value)
        {
            if (value > 0)
                return "+" + value.ToString("0.00") + "% ";
            return value.ToString("0.00") + "% ";
        }

        /// <summary>
        /// 分隔字符串 
        /// </summary>
        public static int[] GetSplitedInts(string src, char separator)
        {
            string[] strs = SplitEx(src, separator);
            List<int> listInt = new List<int>();
            foreach (string tempStr in strs)
            {
                listInt.Add(ConvertUtil.ToInt(tempStr));
            }
            return listInt.ToArray();
        }

        /// <summary>
        /// 将路由的参数标准化为{0}/{1}/{2} 使用此方法后，参数可简写为{{{
        /// </summary>
        public static string GetStandardStringFormatFromRoutePath(string route)
        {
            var count = route.CountOf('{');
            var dest = new StringBuilder();
            for (int index = 0; index < count; index++)
            {
                if (dest.Length > 0)
                    dest.Append('/');
                dest.Append('{');
                dest.Append(index);
                dest.Append('}');
            }
            dest.Insert(0, route.SubstringFromStartToChar('{'));
            return dest.ToString();
        }

        public static string GetStartSpace(this string text)
        => text.Substring(0, text.Length - text.TrimStart().Length);

        /// <summary>
        /// 截取字符串
        /// </summary>
        public static string GetStrAfterKeyword(string str, string mark)
        {
            if (string.IsNullOrEmpty(mark))
                return str;

            int markLastIndex = str.LastIndexOf(mark);

            if (markLastIndex != -1)
                str = str.Substring(markLastIndex + mark.Length, str.Length - (markLastIndex + mark.Length));

            return str;
        }

        /// <summary>
        /// 字符串截取,不添加省略号
        /// </summary>
        public static string GetSubedString(object obj, int length)
        {
            string str = obj.ToString();

            if (string.IsNullOrEmpty(str))
                return string.Empty;

            return (str.Length <= length) ? str : (str.Substring(0, length));
        }

        /// <summary>
        /// 字符串截取,添加省略号
        /// </summary>
        public static string GetSubedStringWhitDot(object obj, int length)
        {
            string str = obj.ToString();

            if (string.IsNullOrEmpty(str))
                return "...";

            return (str.Length <= length) ? str : (str.Substring(0, length) + "...");
        }

        public static string GetText(this IEnumerable<string> lines)
        => JoinToText(lines);

        /// <summary>
        /// 获取当前时间路径
        /// </summary> 
        public static string GetTimePath(string ext = "")
        => DateTime.Now.Info("yyyyMMddHHmmssfff") + ext;

        /// <summary>
        /// 删除换行,空格
        /// </summary>
        public static string GetWarpDeletedTrimedString(string str)
        {
            str = str.Replace("\r", "").Replace("\t", "").Replace("\n", "");
            while (str.Contains("  "))
                str = str.Replace("  ", " ");
            return str;
        }

        /// <summary>
        /// 删除换行,空格
        /// </summary>
        public static string GetWarpTrimedString(string str)
        {
            while (str.Contains("\r\r"))
                str = str.Replace("\r\r", "\r");

            while (str.Contains("\n\n"))
                str = str.Replace("\n\n", "\n");

            while (str.Contains("\r\n\r\n"))
                str = str.Replace("\r\n\r\n", "\r\n");

            while (str.Contains("  "))
                str = str.Replace("  ", " ");

            return str;
        }

        /// <summary>
        /// 固定长度,随机补偿
        /// </summary>
        public static string InitLength(this string value, int length)
        {
            if (value.Length >= length)
                return value.Substring(value.Length - length);
            return RandomUtil.GetString(length - value.Length) + value;
        }

        /// <summary>
        /// 判断字符串是否包含关键字
        /// </summary>
        public static bool IsContain(string str, string[] keys)
        {
            if (string.IsNullOrEmpty(str))
                return false;

            foreach (string key in keys)
            {
                if (str.Contains(key))
                {
                    return true;
                }
            }
            return false;
        }

        /// <summary>
        /// 判断数组是否包含字符串
        /// </summary>
        public static bool IsContain(string[] strings, string str)
        => strings.Contains(str);

        /// <summary>
        /// 判断是否为数字
        /// </summary>
        public static bool IsDigit(string str)
        => int.TryParse(str, out int result);

        /// <summary>
        /// 判断是否包含关键字
        /// </summary>
        public static bool IsKeywordIn(string keyword, string str)
        {
            str = str.ToUpper();
            keyword = keyword.ToUpper();
            return str.Contains(keyword);
        }

        /// <summary>
        /// 判断数组是否包含项目
        /// </summary>
        public static bool IsKeywordIn(string keyword, string[] strs)
        {
            foreach (string s in strs)
            {
                if (s.ToUpper() == keyword.ToUpper())
                {
                    return true;
                }
            }
            return false;
        }

        /// <summary>
        /// 多字符串判空
        /// </summary>
        public static bool IsNullOrEmpty(params string[] strs)
        {
            foreach (string str in strs)
                if (string.IsNullOrEmpty(str))
                    return true;
            return false;
        }

        /// <summary>
        /// 字符串判空
        /// </summary>
        public static bool IsNullOrEmpty(this string str)
        => string.IsNullOrEmpty(str);

        public static bool IsNotEmpty(this object value)
        {
            if (value == null)
                return false;
            return !string.IsNullOrEmpty(value.ToString().Trim());
        }

        public static bool IsEmpty(this object value)
        => value == null ? true : string.IsNullOrEmpty(value.ToString());

        public static string IsEmpty(this string value, string defaultValue)
        => value.IsEmpty() ? defaultValue : value;

        public static bool HasEmpty(params string[] values)
        {
            foreach (var value in values)
                if (value.IsEmpty())
                    return true;
            return false;
        }

        /// <summary>
        /// 多字符串判空
        /// </summary>
        public static bool IsNullOrWhiteSpace(params string[] strs)
        {
            foreach (string str in strs)
                if (string.IsNullOrWhiteSpace(str))
                    return true;
            return false;
        }

        public static bool NotEquals(this string str, params string[] values)
        => !values.Contains(str);

        /// <summary>
        /// 拼接
        /// </summary>
        public static string Join<T>(this IEnumerable<T> values, object separator)
        => string.Join(separator.ToString(), values);

        /// <summary>
        /// 拼接
        /// </summary>
        public static string Join<T>(this IEnumerable<T> values)
        => Join(values, ',');

        /// <summary>
        /// 文本行连接
        /// </summary> 
        public static string JoinToText(this IEnumerable<string> lines)
        => lines.Join("\r\n");

        /// <summary>
        /// 移除字符
        /// </summary>
        public static string Remove(this string text, params char[] removes)
        {
            if (text.IsNullOrEmpty())
                return text;

            var newText = new StringBuilder();
            foreach (char element in text)
                if (!removes.Contains(element))
                    newText.Append(element);
            return newText.ToString();
        }

        /// <summary>
        /// 移除字符串
        /// </summary>
        public static string Remove(this string text, params string[] removes)
        {
            foreach (string remove in removes)
                text = text.Replace(remove, null);
            return text;
        }

        public static string RemoveChar(this string text, char letter)
        => text.Remove(letter.ToString());

        public static string RemoveDigits(this string text)
        => text.Remove(Digits);

        public static string RemoveLetters(this string text)
        => text.Remove(Letters);

        /// <summary>
        /// 删除中间部分 默认删除两头标签
        /// </summary>
        public static string RemoveBetween(this string text, string start, string end, bool containsTag = true)
        => text.Remove(text.GetBetweens(start, end, containsTag));

        public static void RemoveEnd(this StringBuilder sb)
        => sb.Remove(sb.Length - 1, 1);

        /// <summary>
        /// 删除标点
        /// </summary>
        public static string RemovePunctuations(this string text)
        => text.Remove(StringIdentifier.Punctuations);

        /// <summary>
        /// 删除双引号
        /// </summary>
        public static string RemoveQuotations(this string text)
        => text.Remove("\"");

        public static string RemoveWrappings(this string text)
         => text.Remove("\r").Remove("\n");

        /// <summary>
        /// 删除两头双引号
        /// </summary>
        public static string TrimQuotations(this string text)
        {
            if (text[0] == '"' && text[text.Length - 1] == '"')
                return text.Substring(1, text.Length - 2);
            return text;
        }

        /// <summary>
        /// 替换
        /// </summary>
        public static string Replace(this string src, StringStringMap map)
        {
            foreach (var keyValue in map)
                src = src.Replace(keyValue.Key, keyValue.Value);
            return src;
        }

        public static string Replace(this string value, string[] keywords, string target)
        {
            foreach (var keyword in keywords)
                value = value.Replace(keyword, target);
            return value;
        }

        /// <summary>
        /// 替换
        /// </summary>
        public static void Replace(this string[] values, string src, string dest)
        {
            for (int index = 0; index < values.Length; index++)
                values[index] = values[index].Replace(src, dest);
        }

        /// <summary>
        /// 替换头部
        /// </summary>
        public static string ReplaceHead(this string text, string head)
        => head + text.Substring(head.Length);

        /// <summary>
        /// 递归替换，用于单词替换后重组的字符串形成新的关键词的情况
        /// </summary>
        public static string ReplaceRecursive(this string text, string src, string dest)
        {
            while (text.Contains(src))
                text = text.Replace(src, dest);
            return text;
        }

        public static string ReplaceSprit(this string text, bool toRight)
        {
            if (toRight)
                return text.Replace('\\', '/');
            return text.Replace('/', '\\');
        }

        /// <summary>
        /// 替换斜杠 \->/
        /// </summary>
        public static string ReplaceSpritLeft2Right(this string text)
        => text.ReplaceSprit(true);

        /// <summary>
        /// 替换斜杠 /->\
        /// </summary>
        public static string ReplaceSpritRight2Left(this string text)
        => text.ReplaceSprit(false);

        /// <summary>
        /// 文本存储
        /// </summary>
        public static void SaveTo(this string text, string path)
        => FileUtil.Save(path, text);

        /// <summary>
        /// 拆分
        /// </summary>
        public static string[] Split(this string text, object separator, StringSplitOptions option = StringSplitOptions.None)
        => text.Split(new string[] { separator.ToString() }, option);

        /// <summary>
        /// 分隔，保留空值
        /// </summary>
        public static string[] Split(this string value, params string[] separators)
        => value.Split(separators, StringSplitOptions.None);

        /// <summary>
        /// 空格拆分
        /// </summary>
        public static string[] SplitBySpace(this string text)
        => text.Split(StringIdentifier.SpaceSeparators, StringSplitOptions.RemoveEmptyEntries);

        /// <summary>
        /// 分隔字符串 
        /// </summary>
        public static string[] SplitEx(string src, string separator, bool ifTrim = true)
        {
            List<string> listStr = new List<string>();
            int index = src.IndexOf(separator);
            while (index > -1)
            {
                string str = src.Substring(0, index);
                if (ifTrim)
                {
                    str = str.Trim();
                }
                if (!string.IsNullOrEmpty(str))
                {
                    listStr.Add(str);
                }
                src = src.Substring(index + separator.Length);
                index = src.IndexOf(separator);
            }
            if (ifTrim)
            {
                src = src.Trim();
            }
            if (!string.IsNullOrEmpty(src))
            {
                listStr.Add(src);
            }
            return listStr.ToArray();
        }

        /// <summary>
        /// 分隔字符串 
        /// </summary>
        public static string[] SplitEx(this string src, char separator = ',', bool ifTrim = true)
        {
            string[] strs = new string[0];

            if (ifTrim && !string.IsNullOrEmpty(src))
            {
                src = src.Trim();
            }

            if (string.IsNullOrEmpty(src))
            {
                return strs;
            }

            List<string> listStr = new List<string>();
            strs = src.Split(separator);
            if (!ifTrim)
                return strs;
            foreach (string str in strs)
            {
                string str1 = str.Trim();
                if (!string.IsNullOrWhiteSpace(str1))
                    listStr.Add(str1);
            }
            return listStr.ToArray();
        }

        /// <summary>
        /// 分隔字符串 
        /// </summary>
        public static string[] SplitEx(this string[] srcs, char separator = ',', bool ifTrim = true)
        {
            List<string> list = new List<string>();
            foreach (string src in srcs)
                list.AddRange(src.SplitEx(separator, ifTrim));
            return list.ToArray();
        }

        /// <summary>
        /// 分隔，忽略空值
        /// </summary>
        public static string[] SplitAndRemoveEmpty(this string value, params char[] separators)
        => value.Split(separators, StringSplitOptions.RemoveEmptyEntries);

        public static string[] SplitAndRemoveEmpty(this string value, params string[] separators)
        => value.Split(separators, StringSplitOptions.RemoveEmptyEntries);

        /// <summary>
        /// 分隔，忽略空值
        /// </summary>
        public static string[] SplitNoEmpty(this string value, params char[] separators)
        => value.Split(separators, StringSplitOptions.RemoveEmptyEntries);

        /// <summary>
        /// 分隔，忽略空值
        /// </summary>
        public static string[] SplitNoEmpty(this string value, params string[] separators)
        => value.Split(separators, StringSplitOptions.RemoveEmptyEntries);

        public static bool StartsWith(this string text, params string[] keys)
        {
            foreach (var item in keys)
                if (text.StartsWith(item))
                    return true;
            return false;
        }

        /// <summary>
        /// 判断起始字符
        /// </summary>
        public static bool StartsWith(this string text, params char[] anyChars)
        {
            if (text.IsEmpty())
                return false;
            foreach (char ch in anyChars)
                if (text[0] == ch)
                    return true;
            return false;
        }

        public static string SubEnd(this string text, char sperator)
        => text.Substring(text.IndexOf(sperator) + 1);

        public static string SubFront(this string text, char sperator)
        => text.Substring(0, text.IndexOf(sperator));

        /// <summary>
        /// 字符串截取
        /// </summary>
        public static string Substring(this string text, int startIndex, string end, bool needTag = true)
        {
            var endIndex = text.IndexOf(end, startIndex);
            if (needTag)
                endIndex += end.Length;
            return text.SubstringByIndex(startIndex, endIndex);
        }

        /// <summary>
        /// 字符串截取
        /// </summary>
        public static string Substring(this string text, string start, bool needTag = true)
        {
            var startIndex = text.IndexOf(start);
            if (!needTag)
                startIndex += start.Length;
            return text.Substring(startIndex);
        }

        /// <summary>
        /// 截取字符串
        /// </summary>
        public static string Substring(this string text, string start, string end, bool needTag = true)
        {
            if (text.IsNullOrEmpty())
                return null;

            var startIndex = text.IndexOf(start);
            if (startIndex == -1)
                return null;

            startIndex += start.Length;

            var endIndex = text.IndexOf(end, startIndex);
            if (endIndex == -1)
                return null;

            if (needTag)
            {
                endIndex += end.Length;
                startIndex -= start.Length;
            }
            return text.SubstringByIndex(startIndex, endIndex);
        }

        /// <summary>
        /// 截取字符串
        /// </summary>
        public static string SubstringByIndex(this string text, int startIndex, int endIndex)
        => text.Substring(startIndex, endIndex - startIndex);

        /// <summary>
        /// 截取第N个字符
        /// </summary>
        public static string SubstringByKeyIndex(this string text, string key, int index)
        {
            while (text.CountOf(key) > index)
                text = text.Substring(0, text.LastIndexOf(key));
            return text;
        }

        public static string SubstringEndByFirstKey(this string text, char key)
        => SubstringEndByFirstKey(text, key.ToString());

        public static string SubstringEndByFirstKey(this string text, string key)
        {
            if (string.IsNullOrEmpty(text))
                return text;

            var index = text.IndexOf(key);
            if (index == -1)
                return text;

            return text.Substring(index + 1);
        }

        public static string SubstringEndWith(this string text, char key, int count)
        {
            var index = -1;
            while (count-- > 0)
            {
                index = text.IndexOf(key, index + 1);
                if (index == -1)
                    break;
            }
            if (index == -1)
                index = text.Length;
            return text.Substring(0, index);
        }

        public static string SubstringFrom(this string text, string keyword)
        {
            var index = text.IndexOf(keyword);
            if (index == -1)
                return text;
            return text.Substring(index);
        }

        public static string SubstringFromStartToChar(this string text, char key)
        {
            var index = text.IndexOf(key);
            if (index != -1)
                return text.Substring(0, index);
            return text;
        }

        /// <summary>
        /// 字符串截取
        /// </summary>
        public static string SubstringLast(this string text, string start, bool needTag = true)
        {
            var startIndex = text.LastIndexOf(start);
            if (!needTag)
                startIndex += start.Length;
            return text.Substring(startIndex);
        }

        /// <summary>
        /// 截取字符串
        /// </summary>
        public static string[] Substrings(this string text, string start, string end, bool needTag = true)
        {
            var lines = new List<string>();
            if (text.IsNullOrEmpty())
                return lines.ToArray();
            int endIndex = 0;
            while (true)
            {
                int startIndex = text.IndexOf(start, endIndex);
                if (startIndex == -1)
                    break;

                startIndex += start.Length;

                endIndex = text.IndexOf(end, startIndex);
                if (endIndex == -1)
                    break;

                if (needTag)
                    lines.Add(start + text.SubstringByIndex(startIndex, endIndex) + end);
                else
                    lines.Add(text.SubstringByIndex(startIndex, endIndex));

                endIndex += end.Length;
            }
            return lines.ToArray();
        }

        public static string SubstringStartByFirst(this string text, char key)
        => SubstringStartByFirst(text, key.ToString());

        public static string SubstringStartByFirst(this string text, string key)
        {
            var index = text.IndexOf(key);
            if (index == -1)
                return text;
            return text.Substring(0, index);
        }

        /// <summary>
        /// Timestamp
        /// </summary>
        public static string Timestamp(string tail = null)
        => DateTime.Now.GetStamp() + tail;

        public static string ToText(this IEnumerable<string> lines)
        => JoinToText(lines);

        /// <summary>
        /// 去空格和换行
        /// </summary>
        public static string[] Trim(this string[] lines)
        {
            for (int index = 0; index < lines.Length; index++)
                lines[index] = lines[index].Trim();
            return lines;
        }

        public static string[] TrimAndRemoveEmpty(this string[] lines)
        => lines.Select(x => x.Trim()).Where(m => IsNotEmpty(m)).ToArray();

        public static string[] RemoveEmpty(this string[] lines)
        => lines.Where(m => !string.IsNullOrEmpty(m)).ToArray();

        public static string[] Remove(this string[] lines, string keyword)
        => lines.Where(m => m != keyword).ToArray();

        public static string Zero(int length)
        {
            var value = "";
            while (value.Length < length)
                value += "0";
            return value;
        }

        /// <summary>
        /// 字符串前补零
        /// </summary>
        public static string ZeroFill(this object value, int length)
        {
            string str = value.ToString();

            //if (str.Length >= length)
            //    return str.Substring(str.Length - length, length);

            while (str.Length < length)
                str = "0" + str;

            return str;
        }
    }
}
